/***************************************************************************
 *  JLayerME is a JAVA library that decodes/plays/converts MPEG 1/2 Layer 3.
 *  Project Homepage: http://www.javazoom.net/javalayer/javalayerme.html.
 *  Copyright (C) JavaZOOM 1999-2005.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *---------------------------------------------------------------------------
 *   20 Aug 2004 Konstantin Belous 
 *   Changed the code that loads the huffman.dat resource file with purpose 
 *   of compatibility to Netscape Navigator. 
 *
 *   12 Aug 2004 Konstantin Belous 
 *   Added the loadTables() method and moved into it all the code from the HuffmanTables() constructor  
 *   with purposes of compatibility to Microsoft VM. 
 *---------------------------------------------------------------------------
 */
package javazoom.jlme.decoder;


import java.io.ObjectInputStream;

final class HuffmanTables {
    public static HuffmanTables[] ht;
    private final static int MXOFF = 250;
    private final static int HTN = 34;
    private final static int[] bitbuf = new int[32];
    private char tablename0 = ' ';
    private char tablename1 = ' ';
    private char tablename2 = ' ';
    private int xlen;
    private int ylen;
    private int linbits;
    private int linmax;
    private int ref;
    private int[][] val = null;
    private int treelen;
    private static int dmask = 1 << ((4 * 8) - 1);
    private static int hs = 4 * 8;
    private static int point, error, level;

    public static class Huffman {
        static int x, y, v, w;
    }

    private HuffmanTables(String S, int XLEN, int YLEN, int LINBITS, int LINMAX, int REF, int[][] VAL, int TREELEN) throws Exception {
        tablename0 = S.charAt(0);
        tablename1 = S.charAt(1);
        tablename2 = S.charAt(2);
        xlen = XLEN;
        ylen = YLEN;
        linbits = LINBITS;
        linmax = LINMAX;
        ref = REF;
        val = VAL;
        treelen = TREELEN;
    }

    public static void decode(final HuffmanTables h, final Huffman huff, final BitReserve br) {
        point = 0;
        level = dmask;

    /*
    if (h.val == null) {
      return;
    }

    if (h.treelen == 0) {
      huff.x = huff.y = 0;
      return;
    }
    */

        do {
            if (h.val[point][0] == 0) {
                huff.x = h.val[point][1] >>> 4;
                huff.y = h.val[point][1] & 0xf;
                break;
            }

            int[][] temp = h.val;
            if (br.hget1bit() != 0) {
                while (temp[point][1] >= MXOFF) {
                    point += temp[point][1];
                }
                point += temp[point][1];
            } else {
                while (temp[point][0] >= MXOFF) {
                    point += temp[point][0];
                }
                point += temp[point][0];
            }
            level >>>= 1;
            // MDM: ht[0] is always 0;
        } while ((level != 0) || (point < 0));


        if (h.tablename0 == '3' && (h.tablename1 == '2' || h.tablename1 == '3')) {
            huff.v = (huff.y >> 3) & 1;
            huff.w = (huff.y >> 2) & 1;
            huff.x = (huff.y >> 1) & 1;
            huff.y = huff.y & 1;

            if (huff.v != 0) {
                if (br.hget1bit() != 0) {
                    huff.v *= -1; //-v[0];
                }
            }
            if (huff.w != 0) {
                if (br.hget1bit() != 0) {
                    huff.w *= -1; //-w[0];
                }
            }
            if (huff.x != 0) {
                if (br.hget1bit() != 0) {
                    huff.x *= -1; //-x[0];
                }
            }
            if (huff.y != 0) {
                if (br.hget1bit() != 0) {
                    huff.y *= -1; //-y[0];
                }
            }
        } else {
            if (h.linbits != 0) {
                if ((h.xlen - 1) == huff.x) {
                    huff.x += br.hgetbits(h.linbits);
                }
            }
            if (huff.x != 0) {
                if (br.hget1bit() != 0) {
                    huff.x *= -1; //-x[0];
                }
            }
            if (h.linbits != 0) {
                if ((h.ylen - 1) == huff.y) {
                    huff.y += br.hgetbits(h.linbits);
                }
            }
            if (huff.y != 0) {
                if (br.hget1bit() != 0) {
                    huff.y *= -1; //-y[0];
                }
            }
        }
    }

    private void loadTables() {

        int[][] array;
        try (ObjectInputStream in = new ObjectInputStream(getClass().getClassLoader().getResourceAsStream("huffman.ser"))) {
            ht = new HuffmanTables[HTN];
            array = (int[][]) in.readObject();
            ht[0] = new HuffmanTables("0  ", 0, 0, 0, 0, -1, array, 0);
            array = (int[][]) in.readObject();
            ht[1] = new HuffmanTables("1  ", 2, 2, 0, 0, -1, array, 7);
            array = (int[][]) in.readObject();
            ht[2] = new HuffmanTables("2  ", 3, 3, 0, 0, -1, array, 17);
            array = (int[][]) in.readObject();
            ht[3] = new HuffmanTables("3  ", 3, 3, 0, 0, -1, array, 17);
            array = (int[][]) in.readObject();
            ht[4] = new HuffmanTables("4  ", 0, 0, 0, 0, -1, array, 0);
            array = (int[][]) in.readObject();
            ht[5] = new HuffmanTables("5  ", 4, 4, 0, 0, -1, array, 31);
            array = (int[][]) in.readObject();
            ht[6] = new HuffmanTables("6  ", 4, 4, 0, 0, -1, array, 31);
            array = (int[][]) in.readObject();
            ht[7] = new HuffmanTables("7  ", 6, 6, 0, 0, -1, array, 71);
            array = (int[][]) in.readObject();
            ht[8] = new HuffmanTables("8  ", 6, 6, 0, 0, -1, array, 71);
            array = (int[][]) in.readObject();
            ht[9] = new HuffmanTables("9  ", 6, 6, 0, 0, -1, array, 71);
            array = (int[][]) in.readObject();
            ht[10] = new HuffmanTables("10 ", 8, 8, 0, 0, -1, array, 127);
            array = (int[][]) in.readObject();
            ht[11] = new HuffmanTables("11 ", 8, 8, 0, 0, -1, array, 127);
            array = (int[][]) in.readObject();
            ht[12] = new HuffmanTables("12 ", 8, 8, 0, 0, -1, array, 127);
            array = (int[][]) in.readObject();
            ht[13] = new HuffmanTables("13 ", 16, 16, 0, 0, -1, array, 511);
            array = (int[][]) in.readObject();
            ht[14] = new HuffmanTables("14 ", 0, 0, 0, 0, -1, array, 0);
            array = (int[][]) in.readObject();
            ht[15] = new HuffmanTables("15 ", 16, 16, 0, 0, -1, array, 511);
            array = (int[][]) in.readObject();
            ht[16] = new HuffmanTables("16 ", 16, 16, 1, 1, -1, array, 511);
            ht[17] = new HuffmanTables("17 ", 16, 16, 2, 3, 16, (int[][]) array.clone(), 511);
            ht[18] = new HuffmanTables("18 ", 16, 16, 3, 7, 16, (int[][]) array.clone(), 511);
            ht[19] = new HuffmanTables("19 ", 16, 16, 4, 15, 16, (int[][]) array.clone(), 511);
            ht[20] = new HuffmanTables("20 ", 16, 16, 6, 63, 16, (int[][]) array.clone(), 511);
            ht[21] = new HuffmanTables("21 ", 16, 16, 8, 255, 16, (int[][]) array.clone(), 511);
            ht[22] = new HuffmanTables("22 ", 16, 16, 10, 1023, 16, (int[][]) array.clone(), 511);
            ht[23] = new HuffmanTables("23 ", 16, 16, 13, 8191, 16, (int[][]) array.clone(), 511);
            array = (int[][]) in.readObject();
            ht[24] = new HuffmanTables("24 ", 16, 16, 4, 15, -1, array, 512);
            ht[25] = new HuffmanTables("25 ", 16, 16, 5, 31, 24, (int[][]) array.clone(), 512);
            ht[26] = new HuffmanTables("26 ", 16, 16, 6, 63, 24, (int[][]) array.clone(), 512);
            ht[27] = new HuffmanTables("27 ", 16, 16, 7, 127, 24, (int[][]) array.clone(), 512);
            ht[28] = new HuffmanTables("28 ", 16, 16, 8, 255, 24, (int[][]) array.clone(), 512);
            ht[29] = new HuffmanTables("29 ", 16, 16, 9, 511, 24, (int[][]) array.clone(), 512);
            ht[30] = new HuffmanTables("30 ", 16, 16, 11, 2047, 24, (int[][]) array.clone(), 512);
            ht[31] = new HuffmanTables("31 ", 16, 16, 13, 8191, 24, (int[][]) array.clone(), 512);
            array = (int[][]) in.readObject();
            ht[32] = new HuffmanTables("32 ", 1, 16, 0, 0, -1, array, 31);
            array = (int[][]) in.readObject();
            ht[33] = new HuffmanTables("33 ", 1, 16, 0, 0, -1, array, 31);
        } catch (Exception e) {
            System.out.println("couldn't load the Huffman Tables");
            System.exit(1);
        }
    }

    public HuffmanTables() {
        loadTables();
    }

}
